package storage

import (
	"bytes"
	"context"
	"duoke/utils/gconv"
	"duoke/utils/gmd5"
	"duoke/utils/gtime"
	"duoke/utils/redislib"
	"encoding/json"
	"errors"
	"github.com/gin-gonic/gin"
	"github.com/qiniu/go-sdk/v7/auth/qbox"
	"github.com/qiniu/go-sdk/v7/sms/rpc"
	"github.com/qiniu/go-sdk/v7/storage"
	"path/filepath"
	"time"
)

var Qiniu = new(qiniuStorage)

type qiniuStorage struct{}
type FormUploader struct {
	Suffix  string        `json:"suffix"`
	Acid    int           `json:"acid"`
	Setting *StructConfig `json:"setting"`
}

// 本地保存
func (s *qiniuStorage) Save(c *gin.Context, config *StructConfig) (*StructFile, error) {
	fd, headers, err := c.Request.FormFile("file")
	if err != nil {
		return nil, err
	}
	putPolicy := storage.PutPolicy{
		Scope: config.Qiniu.Bucket,
	}
	mac := qbox.NewMac(config.Qiniu.AccessKey, config.Qiniu.SecretKey)
	upToken := putPolicy.UploadToken(mac)
	cfg := storage.Config{}
	// 空间对应的机房
	// cfg.Zone = &storage.ZoneHuadong
	// 是否使用https域名
	// cfg.UseHTTPS = true
	// 上传是否使用CDN上传加速
	// cfg.UseCdnDomains = false
	formUploader := storage.NewFormUploader(&cfg)
	ret := storage.PutRet{}
	//putExtra := storage.
	//{
	//	Params: map[string]string{
	//		"x:name": "github logo",
	//	},
	//}
	err = formUploader.Put(context.Background(), &ret, upToken, config.SavePath+config.SaveName, fd, headers.Size, nil)
	if err != nil {
		return nil, err
	}
	// 文件后缀
	suffix := filepath.Ext(headers.Filename)
	file := StructFile{
		Storage:      "cos",
		OriginalName: headers.Filename,
		Name:         config.SaveName,
		Size:         headers.Size,
		Suffix:       suffix,
		Type:         headers.Header.Get("Content-Type"),
		Path:         config.SavePath + config.SaveName,
		Url:          config.Qiniu.Domain + "/" + config.SavePath + config.SaveName,
	}
	return &file, nil
}

// 删除文件
func (s *qiniuStorage) Del(config *StructConfig, keys []string) error {
	mac := qbox.NewMac(config.Qiniu.AccessKey, config.Qiniu.SecretKey)
	cfg := storage.Config{
		// 是否使用https域名进行资源管理
		// UseHTTPS: true,
	}
	// 指定空间所在的区域，如果不指定将自动探测
	// 如果没有特殊需求，默认不需要指定
	//cfg.Zone=&storage.ZoneHuabei
	bucketManager := storage.NewBucketManager(mac, &cfg)
	//每个batch的操作数量不可以超过1000个，如果总数量超过1000，需要分批发送
	bucket := config.Qiniu.Bucket
	deleteOps := make([]string, 0, len(keys))
	for _, key := range keys {
		deleteOps = append(deleteOps, storage.URIDelete(bucket, key))
	}
	rets, err := bucketManager.Batch(deleteOps)
	if err != nil {
		// 遇到错误
		if _, ok := err.(*rpc.ErrorInfo); ok {
			for _, ret := range rets {
				if ret.Code != 200 {
					return errors.New(ret.Data.Error)
				}
			}
			return errors.New("异常错误")
		} else {
			return err
		}
	} else {
		return nil
	}
}

// 根据url上传视频图片
func (s *qiniuStorage) UploadByURL(config *StructConfig, folder, remoteURL, customFileName string) error {
	mac := qbox.NewMac(config.Qiniu.AccessKey, config.Qiniu.SecretKey)
	cfg := storage.Config{}
	manager := storage.NewBucketManager(mac, &cfg)
	key := folder + "/" + customFileName
	_, err := manager.Fetch(remoteURL, config.Qiniu.Bucket, key)
	if err != nil {
		return err
	}
	return nil
}

// 本地保存
func (s *qiniuStorage) FragmentUpload(c *gin.Context, config *StructConfig) (*StructFile, error) {
	fd, headers, err := c.Request.FormFile("file")
	keyName := "FragmentUpload_" + headers.Filename
	if err != nil {
		return nil, err
	}
	putPolicy := storage.PutPolicy{
		Scope: config.Qiniu.Bucket,
	}
	mac := qbox.NewMac(config.Qiniu.AccessKey, config.Qiniu.SecretKey)
	upToken := putPolicy.UploadToken(mac)
	cfg := storage.Config{}
	// 空间对应的机房
	// cfg.Zone = &storage.ZoneHuadong
	// 是否使用https域名
	// cfg.UseHTTPS = true
	// 上传是否使用CDN上传加速
	cfg.UseCdnDomains = true
	formUploader := storage.NewResumeUploaderV2(&cfg)
	ret := storage.PutRet{}
	//putExtra := storage.
	//{
	//	Params: map[string]string{
	//		"x:name": "github logo",
	//	},
	//}
	err = formUploader.Put(context.Background(), &ret, upToken, config.SavePath+config.SaveName, fd, headers.Size, nil)
	if err != nil {
		return nil, err
	}
	// 文件后缀
	suffix := filepath.Ext(headers.Filename)
	file := StructFile{
		Storage:      "cos",
		OriginalName: headers.Filename,
		Name:         config.SaveName,
		Size:         headers.Size,
		Suffix:       suffix,
		Type:         headers.Header.Get("Content-Type"),
		Path:         config.SavePath + config.SaveName,
		Url:          config.Qiniu.Domain + "/" + config.SavePath + config.SaveName,
	}
	marshal, _ := json.Marshal(file)
	redislib.Redis.Set(c, keyName, marshal, 30*time.Minute)
	return &file, nil
}

// NewFormUploader 上传七牛云([]byte 模式)
func (s *qiniuStorage) NewFormUploader(filename []byte, req *FormUploader) (*StructFile, error) {
	setting := req.Setting
	// 文件后缀
	suffix := req.Suffix
	// 保存路径
	setting.SavePath = "small_program/" + gconv.String(req.Acid) + "/" + gtime.Date(9) + "/"
	// 保存名称
	encrypt := gmd5.MustEncrypt(filename) + suffix
	setting.SaveName = gmd5.MustEncrypt(gconv.String(time.Now().Unix())+encrypt) + suffix
	// 限制大小，2M
	setting.LimitSize = 10
	// 限制文件后缀
	setting.LimitSuffix = "jpeg,jpg,png,gif,mp3,mp4"
	putPolicy := storage.PutPolicy{
		Scope: setting.Qiniu.Bucket,
	}
	mac := qbox.NewMac(setting.Qiniu.AccessKey, setting.Qiniu.SecretKey)
	upToken := putPolicy.UploadToken(mac)
	cfg := storage.Config{}
	formUploader := storage.NewFormUploader(&cfg)
	ret := storage.PutRet{}
	err := formUploader.Put(context.Background(), &ret, upToken, setting.SavePath+setting.SaveName,
		bytes.NewBuffer(filename), int64(len(filename)), nil)
	manager := storage.NewBucketManager(mac, &cfg)
	info, err := manager.Stat(setting.Qiniu.Bucket, ret.Key)
	if err != nil {
		return nil, err
	}
	// 文件后缀
	file := StructFile{
		Storage:      "cos",
		OriginalName: encrypt,
		Name:         setting.SaveName,
		Size:         info.Fsize,
		Suffix:       suffix,
		Type:         info.MimeType,
		Path:         setting.SavePath + setting.SaveName,
		Url:          setting.Qiniu.Domain + "/" + setting.SavePath + setting.SaveName,
	}
	return &file, nil
}

// 根据url上传视频图片
func (s *qiniuStorage) UploadByURLV2(filename string, req *FormUploader) (*StructFile, error) {
	setting := req.Setting
	// 文件后缀
	suffix := req.Suffix
	// 保存路径
	setting.SavePath = "small_program/" + gconv.String(req.Acid) + "/" + gtime.Date(9) + "/"
	// 保存名称
	setting.SaveName = gmd5.MustEncrypt(gconv.String(time.Now().Unix())+filename) + suffix
	// 限制大小，2M
	setting.LimitSize = 10
	// 限制文件后缀
	setting.LimitSuffix = "jpeg,jpg,png,gif,mp3,mp4"
	mac := qbox.NewMac(setting.Qiniu.AccessKey, setting.Qiniu.SecretKey)
	cfg := storage.Config{}
	formUploader := storage.NewBucketManager(mac, &cfg)
	res, err := formUploader.Fetch(filename, setting.Qiniu.Bucket, setting.SavePath+setting.SaveName)
	manager := storage.NewBucketManager(mac, &cfg)
	info, err := manager.Stat(setting.Qiniu.Bucket, res.Key)
	if err != nil {
		return nil, err
	}
	// 文件后缀
	file := StructFile{
		Storage:      "cos",
		OriginalName: filename,
		Name:         setting.SaveName,
		Size:         info.Fsize,
		Suffix:       suffix,
		Type:         info.MimeType,
		Path:         setting.SavePath + setting.SaveName,
		Url:          setting.Qiniu.Domain + "/" + setting.SavePath + setting.SaveName,
	}
	return &file, nil
}
